package edu.commander;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import robocode.AdvancedRobot;
import robocode.BulletHitBulletEvent;
import robocode.BulletHitEvent;
import robocode.BulletMissedEvent;
import robocode.DeathEvent;
import robocode.HitByBulletEvent;
import robocode.HitRobotEvent;
import robocode.HitWallEvent;
import robocode.RobotDeathEvent;
import robocode.RoundEndedEvent;
import robocode.ScannedRobotEvent;
import robocode.SkippedTurnEvent;
import robocode.StatusEvent;
import robocode.WinEvent;
import edu.random.Randonizable;
import edu.random.Randonizador;
import edu.strategy.Factory;
import edu.strategy.Strategy;

public class SimpleCommander implements Commander, Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static Headed headed;
	private static Factory fs;
	private static Behavior currentState = null;
	private static Behavior normal = new Normal();
	private static Behavior stress = new Stress();
	private static int i = 0;
	
	private static long moviment = 100;
	private static long atack = 100;
	private static long evasion = 100;
	
	
	boolean finish = false;
	
	private static Map<String,Strategy> currentsStrategies = new HashMap<String,Strategy>();
	private static Map<String,Randonizador> allStrategies;
	
	public SimpleCommander(Headed headed, Factory fs){
		this.fs = fs;
		this.headed = headed;
		this.setCurrentState();
		prepare();
	}
	
	public void setHeaded(Headed headed){
		this.headed = headed;
		prepare();
	}
	
	private void prepare(){
		System.out.println("Preparando... Moviment(" + moviment + ") Atack(" + atack + ") e Evasion(" + evasion + ")");
		instanceAllRandonizadores();
	}
	private void setCurrentState(){
		currentState = stress;
		currentState = normal;
		fs.getBehaviorCalculator().setBehavior(currentState);
	}
	
	private void instanceAllRandonizadores(){
		try {
			System.out.println("Tentando recuperar HashMap...");
			 allStrategies = fs.getDataManager().getSavedMap();
			Randonizador r = null;
			for (String str : allStrategies.keySet()){
				r = allStrategies.get(str);
				for(Randonizable ran : r.getAll()){
					Strategy s = (Strategy) ran;
					s.setRobot((AdvancedRobot) headed);
				}
			}
			System.out.println("HashMap recuperado!");
		} catch (Exception e){
			System.out.println("Ocorreu um erro. Instanciando HashMap...");
			allStrategies = getInstances();
		}
		
	}
	
	private Map<String,Randonizador> getInstances(){
		Map<String,Randonizador> allStrategies = new HashMap<String,Randonizador>();
		Randonizador r = new Randonizador();
		r.add((ArrayList) fs.getDefault());
		allStrategies.put("default", r);
		
		r = new Randonizador(); 
		r.add((ArrayList) fs.getHitByBullet());
		allStrategies.put("hitbybullet", r);
		
		r = new Randonizador();
		r.add((ArrayList) fs.getHitRobot());
		allStrategies.put("hitrobot", r);
		
		r = new Randonizador();
		r.add((ArrayList) fs.getHitWall());
		allStrategies.put("hitwall", r);
		
		r = new Randonizador();		
		r.add((ArrayList) fs.getScanned());
		allStrategies.put("scanned", r);
		return allStrategies;
	}
	
	@Override
	public void BulletHit(BulletHitEvent e) {
		atackSucessOrFailure((int) (e.getBullet().getPower()*2));
	}
	
	@Override
	public void BulletHitBullet(BulletHitBulletEvent e) {
		atackSucessOrFailure(1);
	}
	
	@Override
	public void BulletMissedHit(BulletMissedEvent e) {
		//atackSucessOrFailure((int) -(e.getBullet().getPower()));
	}

	@Override
	public String getName() {
		return headed.getName();
	}

	private void movimentSucessOrFailure(int sucess){
		if (moviment <= 300 && moviment >= 1)
			moviment +=sucess;
//		for (int i = 0; i < Math.abs(sucess); i++){
//			if (sucess > 0){
//				currentsStrategies.get("default").sucess();
//				currentsStrategies.get("hitrobot").sucess();
//				currentsStrategies.get("hitwall").sucess();
//			} else if (sucess < 0){
//				currentsStrategies.get("default").failure();
//				currentsStrategies.get("hitrobot").failure();
//				currentsStrategies.get("hitwall").failure();
//			}
//		}
	}
	private void evasionSucessOrFailure(int sucess){
		if (evasion <= 300 && evasion >= 1)
			evasion +=sucess;
//		for (int i = 0; i < Math.abs(sucess); i++){
//			if (sucess > 0){
//				currentsStrategies.get("hitbybullet").sucess();
//				currentsStrategies.get("default").sucess();
//			} else if (sucess < 0){
//				currentsStrategies.get("hitbybullet").failure();
//				currentsStrategies.get("default").failure();
//			}
//		}
	}
	private void atackSucessOrFailure(int sucess){
		if (atack <= 300 && atack >= 1)
			atack+=sucess;
//		for (int i = 0; i < Math.abs(sucess); i++){
//			if (sucess > 0){
//				currentsStrategies.get("scanned").sucess();
//			} else if (sucess < 0){
//				currentsStrategies.get("scanned").failure();
//			}
//		}
	}
	
	@Override
	public void HitByBullet(HitByBulletEvent e) {
		movimentSucessOrFailure(-1);
		evasionSucessOrFailure(-2);
	}

	@Override
	public void HitRobot(HitRobotEvent e) {
		//movimentSucessOrFailure(-1);
	}

	private transient int hitWall;
	@Override
	public void HitWall(HitWallEvent e) {
		if (hitWall == 10){
			movimentSucessOrFailure(-1);
			hitWall = 0;
		} else {
			hitWall+=1;
		}
	}

	@Override
	public void RobotDeath(RobotDeathEvent e) {
		movimentSucessOrFailure(5);
		atackSucessOrFailure(5);
		evasionSucessOrFailure(5);
	}
	

	@Override
	public void Scanned(ScannedRobotEvent e) {
		//movimentSucessOrFailure(1);
	}
	
	@Override
	public void WinEvent(WinEvent e) {
		movimentSucessOrFailure(10);
		atackSucessOrFailure(10);
		evasionSucessOrFailure(10);
		End(true);
	}
	
	@Override
	public void Death(DeathEvent e) {
		movimentSucessOrFailure(-5);
		atackSucessOrFailure(-5);
		evasionSucessOrFailure(-5);
		End(false);
	}

	@Override
	public void RoundEnded(RoundEndedEvent e) {
		
	}

	@Override
	public void run() {
		if (!strategyAtackIsOK() && !strategyMovimentIsOK() && !strategyEvasionIsOK() 
				&& SimpleCommander.currentState != SimpleCommander.stress){
			SimpleCommander.currentState = SimpleCommander.stress;
			Factory.getInstance().getBehaviorCalculator().setBehavior(stress);
			System.out.println("I'm stressed! :X");
		} else if (SimpleCommander.currentState != SimpleCommander.normal){
			SimpleCommander.currentState = SimpleCommander.normal;
			Factory.getInstance().getBehaviorCalculator().setBehavior(normal);
			System.out.println("I'm ok ;)!");
		} else {
			System.out.println("Tudo parece estar correndo bem :)");
		}
		i++;
		if ((imStressed() && i > 3) || (!imStressed() && i > 10)){
			i=0;
			if (!strategyAtackIsOK()){
				//Strategy strategy = (Strategy) allStrategies.get("scanned").getRandom(currentsStrategies.get("scanned"));
				Strategy strategy = (Strategy) allStrategies.get("scanned").getRandom();
				currentsStrategies.get("scanned").failure();
				currentsStrategies.put("scanned", strategy);
				
				headed.setScannedStrategy(strategy);
			}
			if (!strategyMovimentIsOK()){
				//Strategy strategyDefault = (Strategy) allStrategies.get("default").getRandom(currentsStrategies.get("default"));
				Strategy strategyDefault = (Strategy) allStrategies.get("default").getRandom();
				currentsStrategies.get("default").failure();
				currentsStrategies.put("default", strategyDefault);
				//Strategy strategyHitWall = (Strategy) allStrategies.get("hitwall").getRandom(currentsStrategies.get("hitwall"));
				Strategy strategyHitWall = (Strategy) allStrategies.get("hitwall").getRandom();
				currentsStrategies.get("hitwall").failure();
				currentsStrategies.put("hitwall", strategyHitWall);
				//Strategy strategyHitRobot = (Strategy) allStrategies.get("hitrobot").getRandom(currentsStrategies.get("hitrobot"));
				Strategy strategyHitRobot = (Strategy) allStrategies.get("hitrobot").getRandom();
				currentsStrategies.get("hitrobot").failure();
				currentsStrategies.put("hitrobot", strategyHitRobot);
				
				headed.setDefaultStrategy(strategyDefault);
				headed.setHitWall(strategyHitWall);
				headed.setHitRobot(strategyHitRobot);
			}
			if(!strategyEvasionIsOK()){
				//Strategy strategyHitByBullet = (Strategy) allStrategies.get("hitbybullet").getRandom(currentsStrategies.get("hitbybullet"));
				Strategy strategyHitByBullet = (Strategy) allStrategies.get("hitbybullet").getRandom();
				currentsStrategies.get("hitbybullet").failure();
				currentsStrategies.put("hitbybullet", strategyHitByBullet);
				//Strategy strategyDefault = (Strategy) allStrategies.get("default").getRandom(currentsStrategies.get("default"));
				Strategy strategyDefault = (Strategy) allStrategies.get("default").getRandom();
				currentsStrategies.get("default").failure();
				currentsStrategies.put("default", strategyDefault);
				
				headed.setHitByBullet(strategyHitByBullet);
				headed.setDefaultStrategy(strategyDefault);
			}
		}
	}
	
	private boolean strategyOK(long value){
		if(imStressed()){
			if (value > 200){
				return true;
			}
			return false;
		} else {
			if (value > 100){
				return true;
			}
			return false;
		}
	}
	private boolean strategyAtackIsOK(){
		return strategyOK(atack);
	}
	private boolean strategyMovimentIsOK(){
		return strategyOK(moviment);
	}
	private boolean strategyEvasionIsOK(){
		return strategyOK(evasion);
	}
	
	
	private boolean imStressed(){
		return SimpleCommander.currentState == SimpleCommander.stress;
	}

	@Override
	public void setTeamMatch(boolean isTeam) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void Skipped(SkippedTurnEvent e) {
		
	}

	@Override
	public void Status(StatusEvent e) {
		
	}


	
	public void End(boolean sucess){
		Strategy str = null;
		for (String s : currentsStrategies.keySet()){
			str = currentsStrategies.get(s);
			if (sucess){
				str.sucess();
			} else {
				str.failure();
			}
		}
		fs.getDataManager().save(allStrategies);
	}

	@Override
	public void giveMeInstruction() {	
		Strategy s = (Strategy) allStrategies.get("scanned").getRandom();
		currentsStrategies.put("scanned", s);
		this.headed.setScannedStrategy(s);
		
		s = (Strategy) allStrategies.get("hitbybullet").getRandom();
		currentsStrategies.put("hitbybullet", (Strategy) s);
		this.headed.setHitByBullet((Strategy) s);
		
		s = (Strategy) allStrategies.get("hitrobot").getRandom();
		currentsStrategies.put("hitrobot", (Strategy) s);
		this.headed.setHitRobot((Strategy) s);
		
		s = (Strategy) allStrategies.get("hitwall").getRandom();
		currentsStrategies.put("hitwall", (Strategy) s);
		this.headed.setHitWall((Strategy) s);
		
		s = (Strategy) allStrategies.get("default").getRandom();
		currentsStrategies.put("default", (Strategy) s);
		this.headed.setDefaultStrategy((Strategy) s);
		
		
	}
}
